using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using XUCore.Ddd.Domain;
using XUCore.NetCore.FreeSql.Entity;
using XUCore.Paging;

namespace XUCore.NetCore.FreeSql.Curd
{
    /// <summary>
    /// CURD服务
    /// </summary>
    /// <typeparam name="TKey">主键类型</typeparam>
    /// <typeparam name="TEntity">数据库实体</typeparam>
    /// <typeparam name="TDto">返回实体</typeparam>
    /// <typeparam name="TCreateCommand">创建命令</typeparam>
    /// <typeparam name="TUpdateCommand">修改命令</typeparam>
    /// <typeparam name="TQueryCommand">查询列表命令</typeparam>
    /// <typeparam name="TQueryPageCommand">查询分页命令</typeparam>
    public abstract class CurdService<TKey, TEntity, TDto, TCreateCommand, TUpdateCommand, TQueryCommand, TQueryPageCommand> :
        CurdService<TKey, TEntity, TDto>,
        ICurdService<TKey, TEntity, TDto, TCreateCommand, TUpdateCommand, TQueryCommand, TQueryPageCommand>
            where TEntity : EntityFull<TKey>, new()
            where TDto : class, new()
            where TCreateCommand : CreateCommand
            where TUpdateCommand : UpdateCommand<TKey>
            where TQueryCommand : ListCommand
            where TQueryPageCommand : PageCommand
    {
        /// <summary>
        /// CURD服务
        /// </summary>
        /// <param name="freeSql"></param>
        /// <param name="mapper"></param>
        /// <param name="user"></param>
        public CurdService(IFreeSql freeSql, IMapper mapper, IUser user) : base(freeSql, mapper, user) { }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        [HttpPost]
        public virtual async Task<TDto> CreateAsync([FromBody] TCreateCommand request, CancellationToken cancellationToken = default)
        {
            var entity = mapper.Map<TCreateCommand, TEntity>(request);

            var res = await repo.InsertAsync(entity, cancellationToken);

            if (res != null)
            {
                CreatedAction?.Invoke(res);

                return mapper.Map<TDto>(res);
            }

            return default(TDto);
        }
        /// <summary>
        /// 修改数据
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        [HttpPut]
        public virtual async Task<int> UpdateAsync([FromBody] TUpdateCommand request, CancellationToken cancellationToken = default)
        {
            var entity = await repo.Select.WhereDynamic(request.Id).ToOneAsync(cancellationToken);

            if (entity == null)
                return 0;

            entity = mapper.Map(request, entity);

            var res = await repo.UpdateAsync(entity, cancellationToken);

            if (res > 0)
                UpdatedAction?.Invoke(entity);

            return res;
        }
        /// <summary>
        /// 查询列表
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        [HttpGet]
        public virtual async Task<List<TDto>> GetListAsync([FromQuery] TQueryCommand request, CancellationToken cancellationToken = default)
        {
            var select = repo.Select.OrderByDescending(c => c.CreatedAt);

            if (request.Limit > 0)
                select = select.Limit(request.Limit);

            var res = await select.ToListAsync(cancellationToken);

            return mapper.Map<List<TDto>>(res);
        }
        /// <summary>
        /// 查询分页列表
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        [HttpGet]
        public virtual async Task<PagedModel<TDto>> GetPageAsync([FromQuery] TQueryPageCommand request, CancellationToken cancellationToken = default)
        {
            var res = await repo.Select
                .OrderByDescending(c => c.CreatedAt)
                .ToPagedListAsync(request.CurrentPage, request.PageSize,
                    includeNestedMembers: false,
                    list => mapper.Map<List<TDto>>(list),
                    cancellationToken);

            return res.ToModel();
        }
    }
}